<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>fetch全套</title>
	</head>
	<body>
		<button id="send">发送请求</button>
		<button id="abort">中断请求</button>
		<div>进度条：<progress id="progress" max="100" value="0"></progress></div>

		<script>
			// 1. GET
			// 2. POST application/json（JSON数据） | application/x-www-form-urlencoded（表单数据） | multipart/form-data boundary（文件上传）
			// 3. 中止请求 | 进度条 | 超时

			/**
			 * 根据后端返回的数据格式，调用下面不同的解析方法。
			 *
			 * text(): 将响应体解析为纯文本字符串返回。
			 * json(): 将响应体解析为 JSON 对象返回。
			 * blob(): 将响应体解析为 Blob 对象返回。
			 * arrayBuffer(): 将响应体解析为 ArrayBuffer 对象返回。
			 * formData(): 将响应体解析为 FormData 对象返回。
			 *
			 * 注意：如果响应体为空，则返回 null。
			 */

			//  发送请求按钮
			const sendBtn = document.getElementById('send')
			sendBtn.addEventListener('click', sendFetch)

			// 中止请求按钮
			const abortBtn = document.getElementById('abort')
			const abort = new AbortController()
			abortBtn.addEventListener('click', () => abort.abort())

			// 进度条
			const progress = document.getElementById('progress')

			async function sendFetch() {
				try {
					const res = fetch('https://jsonplaceholder.typicode.com/todos/1', {
						method: 'GET',
						// 请求头
						headers: {
							// 'Content-Type': 'application/json', // 请求体数据格式
						},
						// 请求体数据
						// body: JSON.stringify({
						// 	title: 'Buy groceries',
						// 	completed: false,
						// }),
						signal: abort.signal, // 中断请求
					})

					// 超时和请求
					const result = await Promise.race([timeoutFetch(5000), res])

					// 【获取当前进度和总进度】
					const response = await result.clone() // 拷贝一份响应体对象数据
					const reader = response.body.getReader() // 获取响应体的 reader 对象（流）
					const total = response.headers.get('Content-Length') // 获取响应体的总长度
					let loaded = 0 // 当前已加载的长度
					// 循环读取响应体数据
					while (true) {
						const { done, value } = await reader.read() // 读取一部分数据
						if (done) break
						loaded += value.length // 累加已加载的长度
						// progress.value = (loaded / total) * 100 // 更新进度条
						progress.value = 100 // 更新进度条
					}

					// 【解析响应体数据】
					const data = await result.json()
					console.log(data)
				} catch (error) {
					console.log(error.toString())
				}
			}

			// 超时
			function timeoutFetch(time = 50) {
				return new Promise((_, reject) => {
					setTimeout(() => {
						abort.abort() // 超时后中止请求
						reject(new Error('请求超时'))
					}, time)
				})
			}
		</script>
	</body>
</html>
